﻿//-----------------------------------------------------------------------------
// Filename: UpdateSettingsController.cs
//
// Description: page controller to handle users settings : password and e-mail.
// 
// History:
// 22 Oct 2007	Guillaume Bonnet	    Created.
//
// License: 
// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2007 Aaron Clauson (aaronc@blueface.ie), Blueface Ltd, Dublin, Ireland (www.blueface.ie)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd. 
// nor the names of its contributors may be used to endorse or promote products derived from this software without specific 
// prior written permission. 
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using log4net;
using MaverickLite.Security;
using BlueFace.Sys;

namespace PasswordRetriever
{
    class UpdateSettingsController : SecureXmlController
    {
        private Hashtable subscriptionData = null;
        private static ILog d_logger = log4net.LogManager.GetLogger("PasswordRetreiver");
        private static string m_adminEmail = AppState.GetConfigSetting("SIPSwitchAdminEmail");
        private StorageLayer m_storagelayer;
        private static string m_dbConnectionStr = AppState.GetConfigSetting("SIPSwitchDBConnStr");
        private static StorageTypes m_StorageType = StorageTypes.Postgresql;
        public int m_minPasswordLength = 0;
        public int m_maxPasswordLength = 0;
        public char[] m_nonAlphaNumAllowedChars = null;

        public UpdateSettingsController(XmlElement initParams): base(initParams)
        {
            m_storagelayer = new StorageLayer(m_StorageType, m_dbConnectionStr);
           
           // Password checking 
            m_nonAlphaNumAllowedChars = new char[]{'!','"','$','%','&','\x27','(',')','*',
										   '+',',','.','/',':','<','=','>','?','@','[',']','^','_','`','{','|','}','~'};
            m_minPasswordLength = 6;
            m_maxPasswordLength = 15;
        }

        protected override void InitialiseRequest(HttpContext context)
        {
            base.InitialiseRequest(context);            
            subscriptionData = MavRequestState.GetRequestData();
        }

        public override void BuildPageModel()
        {
            try
            {             
                string errorStr = null;
                string sipswitchUser = this.m_authenticatedCredentials.Username;

                if (subscriptionData.Count > 1)
                {
                    string isPasswordUpdate = (subscriptionData["passwordupdate"] != null) ? subscriptionData["passwordupdate"] as string : null;
                    string isEmailUpdate = (subscriptionData["emailupdate"] != null) ? subscriptionData["emailupdate"] as string : null;

                    // PASSWORD UPDATE
                    if (isPasswordUpdate != null && isPasswordUpdate.Trim().Length != 0)
                    {
                        string newpassword = (subscriptionData["newpassword"] != null) ? subscriptionData["newpassword"] as string : null;
                        string retypepassword = (subscriptionData["retypepassword"] != null) ? subscriptionData["retypepassword"] as string : null;
                        string oldpassword = (subscriptionData["oldpassword"] != null) ? subscriptionData["oldpassword"] as string : null;

                        // is newpassord = to retypepassword
                        if (newpassword == retypepassword)
                        { 
                            // Verify if the old password is correct
                            DataSet set = null;
                            set = m_storagelayer.GetDataSet("SELECT password FROM Customers WHERE username ='" + sipswitchUser.Replace("'","''") + "'");
                            if (set.Tables[0].Rows.Count != 0)
                            {
                                string DBpass = set.Tables[0].Rows[0]["password"].ToString();
                                if (DBpass == oldpassword)
                                {
                                    if (newpassword.Length >= m_minPasswordLength && newpassword.Length <= m_maxPasswordLength)
                                    {
                                        #region Check the password illegal characters.

                                        char[] passwordChars = newpassword.ToCharArray();

                                        bool illegalCharFound = false;
                                        char illegalChar = ' ';

                                        foreach (char passwordChar in passwordChars)
                                        {
                                            if (Regex.Match(passwordChar.ToString(), "[a-zA-Z0-9]").Success)
                                            {
                                                continue;
                                            }
                                            else
                                            {
                                                bool validChar = false;
                                                foreach (char allowedChar in m_nonAlphaNumAllowedChars)
                                                {
                                                    if (allowedChar == passwordChar)
                                                    {
                                                        validChar = true;
                                                        break;
                                                    }
                                                }

                                                if (validChar)
                                                {
                                                    continue;
                                                }
                                                else
                                                {
                                                    illegalCharFound = true;
                                                    illegalChar = passwordChar;
                                                    break;
                                                }
                                            }
                                        }
                                        #endregion

                                        if (illegalCharFound)
                                        {
                                            m_pageModel.AddAdditionalToModel("<page><status>Your password has an invalid character " + illegalChar + " it can only contain a to Z, 0 to 9 and characters in this set " + SafeXML.MakeSafeXML(new String(m_nonAlphaNumAllowedChars)) + ".</status></page>", false);
                                            return;
                                        }
                                        else
                                        { 
                                            // Save the new password
                                            m_storagelayer.ExecuteNonQuery("UPDATE Customers SET password='" + newpassword + "' WHERE username='" + sipswitchUser + "'");
                                            m_storagelayer.ExecuteNonQuery("UPDATE sipaccounts SET sippassword='" + newpassword + "' WHERE sipusername='" + sipswitchUser + "'");
                                            m_pageModel.AddToModel("<page><status>Your password has been updated successfully.</status></page>", true);
                                        }
                                    }
                                    else
                                    {
                                        m_pageModel.AddToModel("<page><status>Your new password ie either too short or too long, please select a new one between 6 and 15 characters.</status></page>", true);
                                        return;
                                    }
                                }
                                else
                                {
                                    logger.Warn("Update password : The old password is incorrect");
                                    m_pageModel.AddToModel("<page><status>Your old password is incorrect, please enter your details again.</status></page>", true);
                                    return;
                                }                                     
                            }
                            else    // error
                            {
                                errorStr = "An error occured while trying to update customer settings : cannot find user in DB";
                                logger.Error(errorStr);
                                Email.SendEmail(m_adminEmail, "SIPSwitchErrorNotifier", "SIP Switch Error: update settings", errorStr);
                                m_pageModel.AddToModel("<page><status>An error occured while updating your settings. An e-mail has been sent to the community of developpers. Please, try again shortly. Sorry for the inconvenience.</status></page>", true);
                            }
                        }
                        else
                        {
                            m_pageModel.AddToModel("<page><status>Your new password and the one you retype do not match.</status></page>", true);
                            return;
                        }
                    }
                    // EMAIL UPDATE
                    else if (isEmailUpdate != null && isEmailUpdate.Trim().Length != 0)
                    {
                        string newemail = (subscriptionData["newemail"] != null) ? subscriptionData["newemail"] as string : null;

                        if (newemail != null && newemail.Trim().Length != 0)
                        {
                            // Check e-mail format
                            // at least 1 char @  at least 1 char . at least 1 char
                            int at = -1;
                            at = newemail.IndexOf('@');
                            if (at != -1 || at != 0)
                            {
                                int dot = newemail.IndexOf('.', at);
                                if (dot != -1 || dot != 0)
                                { 
                                    // Update e-mail in DB
                                    logger.Debug("UPDATE Customers SET emailaddress='" + newemail.Replace("'","''") + "' WHERE username='" + sipswitchUser + "'");
                                    m_storagelayer.ExecuteNonQuery("UPDATE Customers SET emailaddress='" + newemail.Replace("'", "''") + "' WHERE username='" + sipswitchUser + "'");
                                    m_pageModel.AddToModel("<page><status>Your e-mail has been updated successfully.</status></page>", true);

                                    // Send notification e-mail
                                    string messageBody = "Hi, " + sipswitchUser;
                                    messageBody += "\nYour e-mail has been successfully updated. Thanks for using My SIP Switch.\n\nRegards\nMy SIP Switch Team";
                                    Email.SendEmail(newemail, m_adminEmail, "My SIP Switch Settings Update Notification", messageBody);
                                }
                            }
                            else
                            {
                                m_pageModel.AddToModel("<page><status>The e-mail you entered does not have a correct format.</status></page>", true);
                                return;
                            }
                        }
                        else
                        {
                            errorStr = "An error occured while trying to update customer settings : cannot retreive e-mail info";
                            logger.Error(errorStr);
                            Email.SendEmail(m_adminEmail, "SIPSwitchErrorNotifier", "SIP Switch Error: update settings", errorStr);
                            m_pageModel.AddToModel("<page><status>An error occured while updating your settings. An e-mail has been sent to the community of developpers. Please, try again shortly. Sorry for the inconveniance.</status></page>", true);
                        }
                    }
                    // ERROR
                    else
                    {
                        errorStr = "An error occured while trying to update customer settings : cannot retreive subscription data info";
                        logger.Error(errorStr);
                        Email.SendEmail(m_adminEmail, "SIPSwitchErrorNotifier", "SIP Switch Error: update settings", errorStr);
                        m_pageModel.AddToModel("<page><status>An error occured while updating your settings. An e-mail has been sent to the community of developpers. Please, try again shortly. Sorry for the inconvenience.</status></page>", true);
                    }
                }
                else // At first page loading
                {
                    // Fetch info for this user
                    string customerEmail = null;
                    DataSet set = null;
                    set = m_storagelayer.GetDataSet("SELECT emailaddress FROM Customers WHERE username='" + sipswitchUser.Replace("'","''") + "'");
                    logger.Debug("SELECT emailaddress FROM Customers WHERE username='" + sipswitchUser + "'");
                    if(set.Tables[0].Rows.Count != 0)
                    {
                        customerEmail = set.Tables[0].Rows[0]["emailaddress"].ToString();
                    }
                    else
                    {
                        customerEmail = "No e-mail saved so far !";
                    }

                    m_pageModel.AddToModel("<page><status>Please, fill/edit you details.</status><customeremail>" + customerEmail + "</customeremail></page>", true);
                }

            }
            catch (Exception updateSettingsEx)
            {
                logger.Error("UpdateSettingsController BuildPageModel Exception " + updateSettingsEx.Message);
                Email.SendEmail(m_adminEmail, "SIPSwitchErrorNotifier", "SIP Switch Error: update settings", "UpdateSettingsController BuildPageModel Exception " + updateSettingsEx.Message);
            }
        }
    }
}
